﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using Microsoft.Win32;

using Xc.DataAccess.Core.Extensions;
using Xc.DataAccess.HyperTerminalCore.Models;
using Xc.DataAccess.HyperTerminalCore.Services;
using Xc.Logics.HyperTerminalCore.Udp.Models;
using System.Threading;
using Xc.DataAccess.Core;
using Xc.DataAccess.PcpChannels;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Xc.Logics.HyperTerminalCore.Udp.ViewModels;

namespace Xc.Logics.HyperTerminalCore.Udp.Views
{
    /// <summary>
    /// TerminalView.xaml 的交互逻辑
    /// </summary>
    public partial class TerminalView : UserControl
    {
        private readonly UdpClientOnlineInfo tcpClientInfo;
        private readonly DataHandler dataHandler;
        private readonly IServiceProvider serviceProvider;
        private readonly Encoding encoding;
        public TerminalView(UdpClientOnlineInfo udpClientOnlineInfo, IServiceProvider serviceProvider, Encoding encoding)
        {
            InitializeComponent();
            this.tcpClientInfo = udpClientOnlineInfo;
            udpClientOnlineInfo.ReceiveMessage += UdpClientOnlineInfo_ReceiveMessage;
            udpClientOnlineInfo.SendMessage += UdpClientOnlineInfo_SendMessage;
            GetData();
            this.Unloaded += (s, e) => { };
            dataHandler = new DataHandler(udpClientOnlineInfo, this);

            dataHandler.PcpUpgradeService.Channel.OnUploadUpgradeStatus += Channel_OneUploadUpgradeStatus;
            dataHandler.PcpUpgradeService.Channel.OnUploadUpdateResult += Channel_OnUploadUpdateResult;
            dataHandler.PcpUpgradeService.Channel.OnDevicePackage += Channel_OnDevicePackage;
            this.serviceProvider = serviceProvider.CreateScope().ServiceProvider;
            var option = serviceProvider.GetService<IOptionsSnapshot<AppSetting>>().Value;
            dataHandler.PcpUpgradeService.Option = option.PcpChannelOption;

            this.encoding = encoding;
            if (option.AutoCall)
            {
                CommandBinding_Executed_4(null,null);
            }
        }

        private void UdpClientOnlineInfo_SendMessage(UdpClientOnlineInfo arg1, byte[] arg2)
        {
            AddLog(new ChatInfo($"TX:{arg2.ToHex()}", HorizontalAlignment.Right));
        }

        private PackageInfo GetPackage()
        {
            var svc = serviceProvider.GetService<IOptionsSnapshot<AppSetting>>();
            if (svc.Value.PackageInfo!=null)
            {
                return svc.Value.PackageInfo;
            }
            else
            {
                return null;
            }
        }
        private  async Task<DevicePackageRespond> Channel_OnDevicePackage(DevicePackageRequest arg)
        {
          await  Task.Delay(serviceProvider.GetService<IOptionsSnapshot<AppSetting>>().Value.PcpChannelOption.SendDelayTime);
           var package=  GetPackage();
            if (package == null|| package.PackageInfoItems==null)
            {
                AddLog(new ChatInfo($"设备请求升级包，序号:{arg.PackageIndex},版本:{arg.PackageVersion}", HorizontalAlignment.Left) { RespondMessage= "升级包不存在" });
                return new DevicePackageRespond(DevicePackageRespond.PackageRequest.NotExist, arg.PackageIndex, new byte[] { });
            }
            else
            {
                if (package.Version!=arg.PackageVersion)
                {
                    AddLog(new ChatInfo($"设备请求升级包，序号:{arg.PackageIndex},版本:{arg.PackageVersion}", HorizontalAlignment.Left) { RespondMessage="版本不存在"});
                    return new DevicePackageRespond(DevicePackageRespond.PackageRequest.NotExist, arg.PackageIndex, new byte[] { });
                }
                var pkg= package.PackageInfoItems.Where(p => p.PackageIndex == arg.PackageIndex).FirstOrDefault();
                if (pkg!=null)
                {
                    AddLog(new ChatInfo($"设备请求升级包，序号:{arg.PackageIndex},版本:{arg.PackageVersion}", HorizontalAlignment.Left) {RespondMessage= $"包内容:{pkg.PackageData.ToHex()}" });

                    return new DevicePackageRespond(DevicePackageRespond.PackageRequest.OK, arg.PackageIndex, pkg.PackageData);
                }
                else
                {
                    AddLog(new ChatInfo($"设备请求升级包，序号:{arg.PackageIndex},版本:{arg.PackageVersion}", HorizontalAlignment.Left) { RespondMessage = $"包序号{arg.PackageIndex}不存在" });
                    return new DevicePackageRespond(DevicePackageRespond.PackageRequest.NotExist, arg.PackageIndex, new byte[] { });
                }
            }
        }

        private DeviceUploadUpdateResultRespond Channel_OnUploadUpdateResult(DeviceUploadUpdateResultRequest arg)
        {
            AddLog(new ChatInfo($"设备升级结果:{arg.Status},当前版本:{arg.CurrentVersion}",HorizontalAlignment.Left));
            return new DataAccess.PcpChannels.DeviceUploadUpdateResultRespond
            {
                Status = DeviceUploadUpdateResultRespond.UploadUpdateResult.Success
            };
        }

        private DataAccess.PcpChannels.DeviceUploadUpgradeStatusRespond Channel_OneUploadUpgradeStatus(DataAccess.PcpChannels.DeviceUploadUpgradeStatusRequest arg)
        {
            AddLog(new ChatInfo($"设备升级状态:{arg.Status}",HorizontalAlignment.Left));
            Task.Run(async () => 
            {
               await Task.Delay(2000);
                await DeviceAction("执行升级", async () =>
                {
                    var respond = await dataHandler.PcpUpgradeService.ExecuteUpdate();
                    if (respond.IsSuccess)
                    {
                        return Result.Accept(respond.Data.ToString());
                    }
                    else
                    {
                        return Result.Reject(respond.Message);
                    }
                });
            });
            return new DataAccess.PcpChannels.DeviceUploadUpgradeStatusRespond
            {
                Status=DeviceUploadUpgradeStatusRespond.UploadUpgradeStatus.Ok
            };
        }

        public CancellationTokenSource TokenSource { get; set; } = new CancellationTokenSource();
        private void GetData()
        {
            Task.Run(async () => 
            {
                while (!TokenSource.IsCancellationRequested)
                {
                    List<ChatInfo> infos = new List<ChatInfo>();
                    while (chatInfos.TryDequeue(out var d))
                    {
                        infos.Add(d);
                    }
                    if (infos.Count>0)
                    {
                        this.Dispatcher.Invoke(() =>
                        {
                            AGIN:
                            if (this.ViewModel.ChatInfos.Count > 100)
                            {
                                this.ViewModel.ChatInfos.RemoveAt(0);
                                goto AGIN;
                            }
                            this.ViewModel.ChatInfos.AddRange(infos);
                            ChatLogs.ScrollViewer?.ScrollToEnd();
                        });
                    }

                     await   Task.Delay(100);
                }
            });

        }
        Queue<ChatInfo> chatInfos=new Queue<ChatInfo>();
        private void UdpClientOnlineInfo_ReceiveMessage(UdpClientOnlineInfo arg1, byte[] arg2)
        {
            var chatInfo = new ChatInfo { Caption = arg1.Address, DateTime = DateTime.Now, Alignment = HorizontalAlignment.Left, Content = encoding.GetString(arg2), Status = Status.Success, RespondMessage = null };
            AddLog(chatInfo);
        }
        public async void AddLog(ChatInfo chatInfo)
        {
            chatInfos.Enqueue(chatInfo);
        }

        private void CommandBinding_CanExecute_5(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private async void CommandBinding_Executed_4(object sender, ExecutedRoutedEventArgs e)
        {
          var es=  await  DeviceAction("查询设备版本", async()=> 
            {
                var respond = await dataHandler.PcpUpgradeService.QueryDeviceVersion();
                return respond;
            });
            if (es.IsSuccess)
            {


                 var res=   await  DeviceAction("通知设备升级", async() =>
                    {
                        var package = GetPackage();
                        if (package != null)
                        {
                            if (es.Data.CurrentVersion != package.Version)
                            {
                                var res = await dataHandler.PcpUpgradeService.NewVersionNotify(package.Version, package.PackageSize, package.PackageCount, package.PackageCheck);
                                return res;
                            }
                            return ResultData<CloundNewVersionNotifyRespond>.Reject($"升级包已是最新不需要升级,设备版本:{es.Data.CurrentVersion},服务器版本:{package.Version}");
                        }
                        else
                        {
                            return ResultData<CloundNewVersionNotifyRespond>.Reject("固件升级包不存在");
                        }
                    });

            }
        }
        private async Task<TResult> DeviceAction<TResult>(string title,Func<Task<TResult>> callBack) where TResult : Result
        {
            var chatInfo = new ChatInfo(title,HorizontalAlignment.Right);
            chatInfo.Status = Status.Pending;
            AddLog(chatInfo);
            await Task.Delay(serviceProvider.GetService<IOptionsSnapshot<AppSetting>>().Value.PcpChannelOption.SendDelayTime);
            var respond = await(callBack?.Invoke());
            if (respond.IsSuccess)
            {
                chatInfo.RespondMessage = respond.Message;
                chatInfo.Status = Status.Success;

            }
            else
            {
                chatInfo.RespondMessage = respond.Message;
                chatInfo.Status = Status.Failed;
            }
            return respond;
        }
        private void CommandBinding_CanExecute_4(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void CommandBinding_Executed_3(object sender, ExecutedRoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            if (openFileDialog.ShowDialog() == true)
            {

                Task.Run(async () => 
                {
                    var file = File.OpenRead(openFileDialog.FileName);
                    byte[] vs = new byte[250];
                    int length = 0;
                    bool SendContinue = false;
                    do
                    {
                        length = file.Read(vs, 0, vs.Length);
                        if (length == 0)
                        {
                            break;
                        }
                        var buffer = vs.Take(length).ToArray();
                        SendContinue = await Send(buffer);
                    } while (length > 0 && SendContinue == true);
                });

            }
        }

        private void CommandBinding_CanExecute_3(object sender, CanExecuteRoutedEventArgs e)
        {
            if (ViewModel.ChatInfos.Count > 0)
            {
                e.CanExecute = true;
            }
        }

        private void CommandBinding_Executed_2(object sender, ExecutedRoutedEventArgs e)
        {
            ViewModel.ChatInfos.Clear();
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ViewModel.SendText = string.Empty;
        }

        private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(ViewModel.SendText))
            {
                e.CanExecute = true;
            }
        }

        private void CommandBinding_CanExecute_1(object sender, CanExecuteRoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(ViewModel.SendText))
            {
                e.CanExecute = true;
            }
        }

        private async void CommandBinding_Executed_1(object sender, ExecutedRoutedEventArgs e)
        {
            await Send(ViewModel.SendText);
            ViewModel.SendText = String.Empty;
        }

        private void CommandBinding_CanExecute_2(object sender, CanExecuteRoutedEventArgs e)
        {
            if (_SendTextBox != null && ViewModel.ReturnSend && _SendTextBox.IsFocused)
            {
                if (!string.IsNullOrEmpty(ViewModel.SendText))
                {
                    e.CanExecute = true;
                }
            }
        }
        private async Task<bool> Send(byte[] message)
        {
            var chatInfo = new ChatInfo { Caption = "127.0.0.1", DateTime = DateTime.Now, Alignment = HorizontalAlignment.Right, Content = message.ToHex(), Status = Status.Pending, RespondMessage = null };
            AddLog(chatInfo);
            var res = await tcpClientInfo.Send(message);
            if (res.IsSuccess)
            {
                chatInfo.Status = Status.Success;
                return true;
            }
            else
            {
                chatInfo.Status = Status.Failed;
                chatInfo.RespondMessage = res.Message;
                return false;
            }
        }
        public async Task<bool> Send(string message)
        {
            var chatInfo = new ChatInfo { Caption = "127.0.0.1", DateTime = DateTime.Now, Alignment = HorizontalAlignment.Right, Content = message, Status = Status.Pending, RespondMessage = null };
            AddLog(chatInfo);
            var res = await tcpClientInfo.Send(message, this.ViewModel.AppendLine);
            if (res.IsSuccess)
            {
                chatInfo.Status = Status.Success;
                return true;
            }
            else
            {
                chatInfo.Status = Status.Failed;
                chatInfo.RespondMessage = res.Message;
                return false;
            }
        }

        private void CommandBinding_CanExecute_6(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private async void CommandBinding_Executed_5(object sender, ExecutedRoutedEventArgs e)
        {
            await DeviceAction("执行升级", async () =>
            {
                var respond = await dataHandler.PcpUpgradeService.ExecuteUpdate();
                if (respond.IsSuccess)
                {
                    return Result.Accept(respond.Data.ToString());
                }
                else
                {
                    return Result.Reject(respond.Message);
                }
            });
        }
    }
}
